package com.design.springRetry;


import java.time.LocalTime;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;

/**
 * @author lijiaming
 * @version 1.0
 * @description
 * @date 2025/10/29 11:18
 */
public class TestServiceImpl {

    /**
     * value：抛出指定异常才会重试
     * include：和value一样，默认为空，当exclude也为空时，默认所有异常
     * exclude：指定不处理的异常
     * maxAttempts：最大重试次数，默认3次（包括第一次调用）
     * backoff：重试等待策略，
     * 默认使用@Backoff，@Backoff的value默认为1000L；以毫秒为单位的延迟（默认 1000）;
     * delay：重试的间隔时间,就是value
     * multiplier delay时间的间隔倍数，默认为0，表示固定暂停1秒后进行重试，如果把multiplier设置为1.5，则第一次重试为2秒，第二次为3秒，第三次为4.5秒。
     * @param status
     * @return
     */
    @Retryable(include = {Exception.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public int convertStatus(int status) throws Exception {
        System.out.println("进入convertStatus时间："+ LocalTime.now());
        if (status < 0) {
            throw new Exception("状态小于0是非法的");
        }
        System.out.println("convertStatus: status++");
        return status++;
    }

    /**
     * Spring-Retry还提供了@Recover注解，用于@Retryable重试失败后处理方法。
     * 如果不需要回调方法，可以直接不写回调方法，那么实现的效果是，重试次数完了后，如果还是没成功没符合业务判断，就抛出异常。
     * @Recover标记方法必须要与@Retryable注解的方法“形参”保持一致，第一入参为要重试的异常(一定要是@Retryable方法里抛出的异常或者异常父类)，其他参数与@Retryable保持一致，返回值也要一样，否则无法执行！
     *
     * @param e
     * @param status @Retryable注解的原方法参数，可以保留，也可以不要。
     * @return
     */
    @Recover
    public int recover(Exception e, int status) {
        //记日志到数据库 或者调用其余的方法
        System.out.println(String.format("兜底方法执行，异常信息:%s,status:%d", e.toString(), status));
        return -1;
    }
}
